package com.z.security.config;

import com.alibaba.fastjson.JSON;
import com.z.result.ResultWrapper;
import com.z.security.entity.SecurityAdmin;
import com.z.security.entity.vo.LoginSuccessReturnVO;
import com.z.security.filter.JWTCheckFilter;
import com.z.service.UsersService;
import com.z.utils.token.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@EnableWebSecurity

public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsService userDetailsService;

    @Autowired
    UsersService usersService;

    @Bean
    public BCryptPasswordEncoder getPassWorldEncoder(){

        return new BCryptPasswordEncoder();
    }



    @Override
    public void configure(WebSecurity web) throws Exception {
        //忽略swagger3所需要用到的静态资源，允许访问
        web.ignoring().antMatchers( "/swagger-ui.html",
                "/swagger-ui/**",
                "/swagger-resources/**",
                "/v2/api-docs",
                "/v3/api-docs",
                "/webjars/**",
                "swagger-ui/index.html");
    }


    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
        // super.configure(auth);

        // 基于数据库的认证
        builder.userDetailsService(userDetailsService)
        .passwordEncoder(getPassWorldEncoder()); // 加密
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // super.configure(http);
        // 授权请求
        http.authorizeRequests()
                .antMatchers("/login/**").permitAll()
                .antMatchers("/easy-captcha/**").permitAll();


        // 定制登录
        http.formLogin()
                .usernameParameter("loginAcct") // 定制登录账号的请求参数名
                .passwordParameter("userPswd")
                .loginProcessingUrl("/login/do/Login").permitAll() // 处理登录请求的url
                .failureHandler(getFailureHandler())
                .successHandler(getSuccessHandler()); // 认证通过后的事件处理（在这里返回token等必要的用户信息）

        http.httpBasic().disable();
        http.csrf().disable();

        http.addFilterAfter(new JWTCheckFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    // 自定义认证失败时的控制器
    private AuthenticationFailureHandler getFailureHandler() {
        return new AuthenticationFailureHandler(){

            @Override
            public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {

                httpServletResponse.setCharacterEncoding("utf-8");
                httpServletResponse.setContentType("application/json;charset=utf-8");

                PrintWriter writer = httpServletResponse.getWriter();
                System.out.println("认证失败");

                writer.println(JSON.toJSON(ResultWrapper.getFailBuilder().msg("认证失败").build()));
                writer.flush();
                writer.close();

            }
        };
    }

    // 自定义认证成功时的控制器
    private AuthenticationSuccessHandler getSuccessHandler() {

        return new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                httpServletResponse.setCharacterEncoding("utf-8");
                httpServletResponse.setContentType("application/json;charset=utf-8");
                // 拿到认证的用户
                SecurityAdmin admin = (SecurityAdmin) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

                Map<String,Object> dataMap = new HashMap<>();

                // 获取需要的用户信息
                dataMap.put("userId",admin.getOriginalAdmin().getId().toString());

                // 生成token，载荷中装有用户id
                String token = JwtUtil.createToken(dataMap.get("userId").toString());

                System.out.println("认证成功");

                // 返回数据
                PrintWriter writer = httpServletResponse.getWriter();
                writer.print(JSON.toJSON(ResultWrapper.getSuccessBuilder().data(new LoginSuccessReturnVO(token,dataMap.get("userId").toString())).msg("认证成功").build()));
                writer.flush();
                writer.close();

            }
        };
    }
}
